<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="h9y2B" id="h9y2B"><span data-lake-id="ucceb0590" id="ucceb0590">典型回答</span></h1>
  <p data-lake-id="u3d6e7f3f" id="u3d6e7f3f"><br></p>
  <p data-lake-id="u5997e792" id="u5997e792"><span data-lake-id="ud423b90a" id="ud423b90a">所谓乐观锁，其实就是基于CAS的机制，CAS的本质是Compare And Swap，就是需要知道一个key在修改前的值，去进行比较。</span></p>
  <p data-lake-id="u1e789030" id="u1e789030"><span data-lake-id="u2cb3314f" id="u2cb3314f">​</span><br></p>
  <p data-lake-id="u83e7c05a" id="u83e7c05a"><span data-lake-id="u4d6cdc08" id="u4d6cdc08">在Redis中，想要实现这个功能，我们可以依赖 WATCH 命令。这个命令一旦运行，他会确保只有在 WATCH 监视的键在调用 EXEC 之前没有改变时，后续的事务才会执行。</span></p>
  <p data-lake-id="u4213acd4" id="u4213acd4"><span data-lake-id="u777d7498" id="u777d7498">​</span><br></p>
  <p data-lake-id="u1bc26009" id="u1bc26009"><span data-lake-id="u80e68b64" id="u80e68b64">例如，如果没有 INCRBY，我们可以用下面的方式实现原子的增量操作：</span></p>
  <p data-lake-id="u3a1c1a83" id="u3a1c1a83"><span data-lake-id="ua5d3483b" id="ua5d3483b">​</span><br></p>
  <pre lang="java"><code>
WATCH counter
GET counter
MULTI
SET counter &lt;从 GET 获得的值 + 任何增量&gt;
EXEC
</code></pre>
  <p data-lake-id="u7de3298b" id="u7de3298b"><br></p>
  <ol list="u97889b16">
   <li fid="ufbe888b2" data-lake-id="u7b1dfcb1" id="u7b1dfcb1" data-lake-index-type="true"><strong><span data-lake-id="u95ccf24c" id="u95ccf24c">WATCH</span></strong><span data-lake-id="u6dec39eb" id="u6dec39eb">：使用 WATCH 命令监视一个或多个键。这个命令会监视给定键直到事务开始（即执行 MULTI 命令）。</span></li>
   <li fid="ufbe888b2" data-lake-id="u2df5130b" id="u2df5130b" data-lake-index-type="true"><strong><span data-lake-id="ucd5ac235" id="ucd5ac235">GET</span></strong><span data-lake-id="u073cd25a" id="u073cd25a">：在事务开始之前，查询你需要的数据。</span></li>
   <li fid="ufbe888b2" data-lake-id="u7abce0a3" id="u7abce0a3" data-lake-index-type="true"><strong><span data-lake-id="u87c6cc18" id="u87c6cc18">MULTI</span></strong><span data-lake-id="ua4f83b86" id="ua4f83b86">：使用 MULTI 命令开始事务。</span></li>
   <li fid="ufbe888b2" data-lake-id="u04611868" id="u04611868" data-lake-index-type="true"><strong><span data-lake-id="u79e4de2b" id="u79e4de2b">SET</span></strong><span data-lake-id="udea7407b" id="udea7407b">：在事务中添加所有需要执行的命令。</span></li>
   <li fid="ufbe888b2" data-lake-id="ubad60308" id="ubad60308" data-lake-index-type="true"><strong><span data-lake-id="u4ca38b6b" id="u4ca38b6b">EXEC</span></strong><span data-lake-id="u1e14f897" id="u1e14f897">：使用 EXEC 命令执行事务。如果自从事务开始以来监视的键被修改过，EXEC 将返回 nil，这表示事务中的命令没有被执行。</span></li>
  </ol>
  <p data-lake-id="u87979f15" id="u87979f15"><span data-lake-id="u81529a27" id="u81529a27">​</span><br></p>
  <p data-lake-id="u57b1a49f" id="u57b1a49f"><span data-lake-id="u80215dfb" id="u80215dfb">通过这种方式，Redis 保证了只有在监视的数据自事务开始以来没有改变的情况下，事务才会执行，从而实现了乐观锁定。</span></p>
  <p data-lake-id="u30c632e7" id="u30c632e7"><span data-lake-id="u0a8b3026" id="u0a8b3026">​</span><br></p>
  <p data-lake-id="u61cb91f1" id="u61cb91f1"><span data-lake-id="uc690c242" id="uc690c242">以下，是在Java中，用Jedis实现的代码，和上述流程是一样的：</span></p>
  <p data-lake-id="u238e2373" id="u238e2373"><span data-lake-id="u38e0bcad" id="u38e0bcad">​</span><br></p>
  <pre lang="java"><code>
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;

public class RedisOptimisticLock {
    public static void main(String[] args) {
        // 连接到 Redis
        Jedis jedis = new Jedis("localhost");

        try {
            // 监视键
            String key = "myKey";
            jedis.watch(key);

            // 模拟从数据库读取最新值
            String value = jedis.get(key);
            int intValue = Integer.parseInt(value);

            // 开始事务
            Transaction t = jedis.multi();

            // 在事务中执行操作
            t.set(key, String.valueOf(intValue + 1));

            // 尝试执行事务
            if (t.exec() == null) {
                System.out.println("事务执行失败，数据已被其他客户端修改");
            } else {
                System.out.println("事务执行成功");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            jedis.close();
        }
    }
}

</code></pre>
  <p data-lake-id="ub03149e4" id="ub03149e4"><br></p>
  <p data-lake-id="ubb5d12a7" id="ubb5d12a7"><br></p>
 </body>
</html>